/*
 * Provider.cs
 *
 * This class is used to instaniate the correct BLAS, LAPACK,
 * and FFT providers.
 *
 * Copyright (c) 2005, dnAnalytics. All rights reserved.
 */

#region Using Directives

using System.Globalization;
using dnAnalytics.Nli.Atlas;

#endregion Using Directives

namespace dnAnalytics.Nli {
	/// <summary>
	/// Enumerates the valid BLAS providers.
	/// </summary>
	public enum BlasProvider {
		/// <summary>
		/// Use Intel's Math Kernel Library as the native BLAS provider.
		/// </summary>
		Mkl,

		/// <summary>
		/// Use ATLAS as the native BLAS provider.
		/// </summary>
		Atlas,
		//Amd
		//,VecLib
	} ;

	/// <summary>
	/// Enumerates the valid LAPACK providers.
	/// </summary>
	public enum LapackProvider {
		/// <summary>
		/// Use Intel's Math Kernel Library as the native BLAS provider.
		/// </summary>
		Mkl,

		/// <summary>
		/// Use CLAPACK as the LAPACK provider.
		/// </summary>
		/// <remarks>Optimized ATLAS LAPACK routines are for these LAPACK routines<br/>
		/// * [S,D,C,Z]GESV
		/// * [S,D,C,Z]GETRF
		/// * [S,D,C,Z]GETRS
		/// * [S,D,C,Z]GETRI
		/// * [S,D,C,Z]TRTRI
		/// * [S,D,C,Z]POSV
		/// * [S,D,C,Z]POTRF
		/// * [S,D,C,Z]POTRS
		/// * [S,D,C,Z]POTRI
		/// * [S,D,C,Z]LAUUM </remarks>
		Clapack,
		//Amd
		//,VecLib
	} ;

	/// <summary>
	/// The Provider class is used to specify which native libraries to use. The libraries can be set via properties or a the dll config file (dnAnalytics.NLI.dll.config).
	/// The config contains to settings under configuration/appSettings, dnAnalytics.blas.dll and dnAnalytics.lapack.dll
	/// <code>
	/// <configuration>
	///    <appSettings>
	///        <add key="dnAnalytics.blas.dll" value="ATLAS" />
	///        <add key="dnAnalytics.lapack.dll" value="CLAPACK" />
	///    </appSettings>
	/// </configuration>
	/// </code>
	/// </summary>
	public sealed class Provider {
		#region Fields

		private static IBlas blas = dnAnalytics.Nli.Atlas.Blas.Instance;
		private static ILapack lapack = Clapack.Instance;
		private static BlasProvider blasProvider = BlasProvider.Atlas;
		private static LapackProvider lapackProvider = LapackProvider.Clapack;

		internal const string mklDll = "mkl.dll";
		internal const string atlasDll = "atlas.dll";
		//internal const string amdDll = "amd.dll";
		internal const string clapackDll = "atlas.dll";
		//internal const string vecLibDll = "vecLib.dll";

		private static int blockSize = 16;

		#endregion Fields

		#region Constructors

		static Provider() {
			string blas = ConfigurationReader.Setting("dnAnalytics.blas.dll");
			if (blas != null) {
				if (string.Compare(blas, "mkl", true, CultureInfo.InvariantCulture) == 0) {
					blasProvider = BlasProvider.Mkl;
				} else if (string.Compare(blas, "atlas", true, CultureInfo.InvariantCulture) == 0) {
					blasProvider = BlasProvider.Atlas;
				} //else if (string.Compare(blas, "amd", true, CultureInfo.InvariantCulture) == 0) {
				//blasProvider = BlasProvider.Amd;
				//}
				//else if (string.Compare(blas, "veclib", true, CultureInfo.InvariantCulture) == 0) {
				//	blasProvider = BlasProvider.VecLib;
				//}
			}

			string lapack = ConfigurationReader.Setting("dnAnalytics.lapack.dll");
			if (lapack != null) {
				if (string.Compare(lapack, "mkl", true, CultureInfo.InvariantCulture) == 0) {
					lapackProvider = LapackProvider.Mkl;
				} else if (string.Compare(lapack, "clapack", true, CultureInfo.InvariantCulture) == 0) {
					lapackProvider = LapackProvider.Clapack;
				} //else if (string.Compare(lapack, "amd", true, CultureInfo.InvariantCulture) == 0) {
				//lapackProvider = LapackProvider.Amd;
				//}
				//else if (string.Compare(lapack, "veclib", true, CultureInfo.InvariantCulture) == 0) {
				//lapackProvider = LapackProvider.VecLib;
				//}
			}
		}

		private Provider() {}

		#endregion Constructors

		#region Properties

		/// <summary>
		/// The block size to use for blocked LAPACK alogrithms. The value must be positive and generally between 16 and 64.
		/// </summary>
		public static int BlockSize {
			get { return blockSize; }
			set {
				if (value > 0) {
					blockSize = value;
				}
			}
		}

		/// <summary>
		/// The BLAS provider to user.
		/// </summary>
		public static BlasProvider BlasProvider {
			get { return blasProvider; }
			set {
				blasProvider = value;
				switch (blasProvider) {
					case BlasProvider.Mkl:
						blas = dnAnalytics.Nli.Mkl.Blas.Instance;
						break;
						//case BlasProvider.Amd:
						//	blas = Amd.Instance;
						//	break;
					case BlasProvider.Atlas:
						blas = dnAnalytics.Nli.Atlas.Blas.Instance;
						break;
						//case BlasProvider.VecLib:
						//	blas = VecLib.Instance;
						//	break;
				}

			}
		}

		/// <summary>
		/// The LAPACK provider to use.
		/// </summary>
		public static LapackProvider LapackProvider {
			get { return lapackProvider; }
			set {
				lapackProvider = value;
				switch (lapackProvider) {
					case LapackProvider.Mkl:
						lapack = dnAnalytics.Nli.Lapack.Lapack.Instance;
						break;
						//case LapackProvider.Amd:
						//lapack = Amd.Instance;
						//	break;
					case LapackProvider.Clapack:
						lapack = Clapack.Instance;
						break;
						//case LapackProvider.VecLib:
						//lapack = VecLib.Instance;
						//break;
				}

			}
		}

		//		public static string FftDll{get;set;}


		/// <summary>
		/// A reference to the current BLAS provider.
		/// </summary>
		public static IBlas Blas {
			get { return blas; }
		}

		/// <summary>
		/// A reference to the current LAPACK provider.
		/// </summary>
		public static ILapack Lapack {
			get { return lapack; }
		}

		#endregion Properties
	}
}